﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace BDSim
{

    /// <summary>
    /// 导航服务性能类，包含计算导航服务性能的方法
    /// </summary>
    public class DopDLL
    {
        /// <summary>
        /// 导航服务性能计算输入结构体
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        struct DopInput
        {
            /// <summary>
            /// 用户坐标,纬经高(UserPos[0]:纬度，UserPos[1]：经度，UserPos[2]：高)，单位为度,纬度的绝对值必须小于90度，经度的范围为【-180，180】
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public double[] UserBLHPos;

            /// <summary>
            /// 截止高度角，单位为度
            /// </summary>
            public double Elelim;

            /// <summary>
            /// UERE预算值，Seta[0~4]f分别表示广播星历及时钟、残留电离层、对流层、多径、接收机噪声误差 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
            public double[] Seta;
        }

        /// <summary>
        /// 导航服务性能计算输出结构体
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DopOutput
        {
            /// <summary>
            /// 几何精度因子
            /// </summary>
            public double GDOP;

            /// <summary>
            /// 位置精度因子
            /// </summary>
            public double PDOP;

            /// <summary>
            /// 水平精度因子
            /// </summary>
            public double HDOP;

            /// <summary>
            /// 垂直精度因子
            /// </summary>
            public double VDOP;

            /// <summary>
            /// 时间精度因子
            /// </summary>
            public double TDOP;

            /// <summary>
            /// 可见星数目
            /// </summary>
            public int AccessNum;

            public double HNSP;
            public double VNSP;
            public double PNSP;
            public double TNSP;
        }

        /// <summary>
        /// 纬经高结构体，表示多个卫星的位置
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct BLHData
        {
            /// <summary>
            /// 卫星位置，从SatsBLH[0]开始按照纬度（单位为度）、经度（单位为度）、高（单位为米）的顺序依次表示卫星位置
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 450)]
            public double[] SatsBLH;
        }

        /// <summary>
        /// 导航性能分析计算    
        /// </summary>
        /// <param name="B">纬度（单位为度）</param>
        /// <param name="L">经度（单位为度）</param>
        /// <param name="H">高度（单位为米）</param>
        /// <param name="EleLim">截止高度角（单位为度）</param>
        /// <param name="dopoutput">导航性能参数</param>
        public static void CalDop(DopEnum type, double B, double L, double H, double EleLim, out DopOutput dopoutput)
        {
            DopInput dopinput = new DopInput();
            dopinput.UserBLHPos = new double[] { B, L, H };
            dopinput.Elelim = EleLim;
            double[] Seta = new double[5];
            Seta[0] = 1.1 + 0.8;  //广播时钟、广播星历误差 
            Seta[1] = 0.1;		//残留电离层延迟 
            Seta[2] = 0.2;		//残留对流层延迟 
            Seta[3] = 0.1;		//接收机噪声和分辨率 
            Seta[4] = 0.2;		//多径 
            dopinput.Seta = Seta;
            CalDOP(type, dopinput, out dopoutput);
        }

        /// <summary>
        /// 导航性能分析计算  
        /// </summary>
        /// <param name="B">纬度（单位为度）</param>
        /// <param name="L">经度（单位为度）</param>
        /// <param name="H">高度（单位为米）</param>
        /// <param name="EleLim">截止高度角（单位为度）</param>
        /// <param name="Seta">UERE预算值，包括广播星历及时钟、残留电离层、对流层、多径、接收机噪声误差</param>
        /// <param name="dopoutput">导航性能参数</param>
        public static void CalDop(DopEnum type, double B, double L, double H, double EleLim, double[] Seta, out DopOutput dopoutput)
        {
            DopInput dopinput = new DopInput();
            dopinput.UserBLHPos = new double[] { B, L, H };
            dopinput.Elelim = EleLim;
            dopinput.Seta = Seta;
            CalDOP(type, dopinput, out dopoutput);
        }

        /// <summary>
        /// 导航性能分析计算  
        /// </summary>
        /// <param name="B">纬度（单位为度）</param>
        /// <param name="L">经度（单位为度）</param>
        /// <param name="H">高度（单位为米）</param>
        /// <param name="EleLim">截止高度角（单位为度）</param>
        /// <param name="dopoutput">导航性能参数</param>
        /// <param name="IsLinkConsidered">标识，是否考虑星间链路，true表示考虑，false表示不考虑</param>
        public static void CalDop(DopEnum type, double B, double L, double H, double EleLim, out DopOutput dopoutput, bool IsLinkConsidered)
        {
            if (IsLinkConsidered)
            {
                double[] Seta = new double[5] { 0.5, 0.1, 0.2, 0.1, 0.2 };
                CalDop(type, B, L, H, EleLim, Seta, out dopoutput);
            }
            else
            {
                CalDop(type, B, L, H, EleLim, out dopoutput);
            }
        }

        /// <summary>
        /// 计算一个固定地面点的导航服务性能（DOP、NSP及可见性），使用本函数前必须先调用SetSatsPos函数
        /// </summary>
        /// <param name="dopinput">导航服务性能输入结构体</param>
        /// <param name="dopoutput">导航服务性能输出结构体</param>
        /// <returns>int 型，输入超界返回0，成功返回1,返回-1表示可见星数目小于4；-2表示没有设置卫星位置，即没有正确调用SetSatsPos函数</returns>
        [DllImport("DopDLL.dll", EntryPoint = "CalDOP", CallingConvention = CallingConvention.Cdecl)]
        static extern int CalDOP(DopEnum type, DopInput dopinput, out DopOutput dopoutput);

        /// <summary>
        /// 设置卫星位置，把卫星位置赋给动态库中的SatsPos
        /// </summary>
        /// <param name="Sat">卫星位置的一维数组，ECF坐标,单位为米，从Sat[0]开始依次表示X、Y、Z</param>
        /// <param name="SatNum">卫星总数</param>
        /// <returns>int型，0表示卫星位置数量与卫星数目不符合，1表示计算成功</returns>
        [DllImport("DopDLL.dll", EntryPoint = "SetSatsPos", CallingConvention = CallingConvention.Cdecl)]
        public static extern int SetSatsPos(double[] Sat, int SatNum);

        /// <summary>
        /// 获取一组卫星位置，使用本函数前必须先调用SetSatsPos函数
        /// </summary>
        /// <param name="blh">所有卫星位置</param>
        /// <returns>int型，1表示计算成功，0表示没有调用SetSatsPos函数或者调用不正确</returns>
        [DllImport("DopDLL.dll", EntryPoint = "GetSatsBLH", CallingConvention = CallingConvention.Cdecl)]
        public static extern int GetSatsBLH(ref BLHData blh);
    }
}
